package com.unicloud.medical.oss.grpc;

import com.google.protobuf.ByteString;
import com.google.protobuf.ProtocolStringList;
import com.unicloud.medical.oss.common.model.FileMetaData;
import com.unicloud.medical.oss.common.model.request.*;
import com.unicloud.medical.oss.common.util.GrpcResultDTOUtil;
import com.unicloud.medical.oss.core.DefaultEndpoint;
import com.unicloud.medical.oss.service.grpc.*;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@GrpcService
public class OSSGrpcEndpoint extends OSSServiceGrpc.OSSServiceImplBase {

    private DefaultEndpoint defaultEndpoint;

    public OSSGrpcEndpoint(DefaultEndpoint defaultEndpoint) {
        this.defaultEndpoint = defaultEndpoint;
    }

    @Override
    public void bucketExist(BucketExistGrpcRequest request, StreamObserver<GrpcResultDTO> responseObserver) {
        responseObserver.onNext(bucketExist(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTO bucketExist(BucketExistGrpcRequest request) {
        BucketExistRequest bucketExistRequest = new BucketExistRequest(request.getBucketName());
        bucketExistRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.toGrpc(defaultEndpoint.bucketExist(bucketExistRequest));
    }

    @Override
    public void createBucket(CreateBucketGrpcRequest request, StreamObserver<GrpcResultDTO> responseObserver) {
        responseObserver.onNext(createBucket(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTO createBucket(CreateBucketGrpcRequest request) {
        CreateBucketRequest createBucketRequest = new CreateBucketRequest(request.getBucketName());
        createBucketRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.toGrpc(defaultEndpoint.createBucket(createBucketRequest));
    }

    @Override
    public void createDefaultPolicyBucket(CreateBucketGrpcRequest request, StreamObserver<GrpcResultDTO> responseObserver) {
        responseObserver.onNext(createDefaultPolicyBucket(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTO createDefaultPolicyBucket(CreateBucketGrpcRequest request) {
        CreateBucketRequest createBucketRequest = new CreateBucketRequest(request.getBucketName());
        createBucketRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.toGrpc(defaultEndpoint.createDefaultPolicyBucket(createBucketRequest));
    }

    @Override
    public void removeBucket(DeleteBucketGrpcRequest request, StreamObserver<GrpcResultDTO> responseObserver) {
        responseObserver.onNext(removeBucket(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTO removeBucket(DeleteBucketGrpcRequest request) {
        DeleteBucketRequest deleteBucketRequest = new DeleteBucketRequest(request.getBucketName());
        deleteBucketRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.toGrpc(defaultEndpoint.removeBucket(deleteBucketRequest));
    }

    @Override
    public void getAllBuckets(CommonGrpcRequest request, StreamObserver<GrpcResultDTOV5> responseObserver) {
        responseObserver.onNext(getAllBuckets(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV5 getAllBuckets(CommonGrpcRequest request) {
        CommonRequest commonRequest = new CommonRequest();
        commonRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV5(defaultEndpoint.getAllBuckets(commonRequest));
    }

    @Override
    public void listAllObjectsCurrBucket(ListAllObjectsCurrBucketGrpcRequest request, StreamObserver<GrpcResultDTOV4> responseObserver) {
        responseObserver.onNext(listAllObjectsCurrBucket(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV4 listAllObjectsCurrBucket(ListAllObjectsCurrBucketGrpcRequest request) {
        ListAllObjectsCurrBucketRequest listAllObjectsCurrBucketRequest = new ListAllObjectsCurrBucketRequest(request.getBucketName());
        listAllObjectsCurrBucketRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV4(defaultEndpoint.listAllObjectsCurrBucket(listAllObjectsCurrBucketRequest));
    }

    @Override
    public void listObjectsCurrBucketAndFolder(ListAllObjectsCurrBucketAndFolderGrpcRequest request, StreamObserver<GrpcResultDTOV4> responseObserver) {
        responseObserver.onNext(listObjectsCurrBucketAndFolder(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV4 listObjectsCurrBucketAndFolder(ListAllObjectsCurrBucketAndFolderGrpcRequest request) {
        ListAllObjectsCurrBucketAndFolderRequest listAllObjectsCurrBucketAndFolderRequest = new ListAllObjectsCurrBucketAndFolderRequest(request.getBucketName(), request.getFolder());
        listAllObjectsCurrBucketAndFolderRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV4(defaultEndpoint.listObjectsCurrBucketAndFolder(listAllObjectsCurrBucketAndFolderRequest));
    }

    @Override
    public StreamObserver<UploadObjectGrpcRequest> uploadObject(StreamObserver<GrpcResultDTOV2> responseObserver) {
        return new StreamObserver<UploadObjectGrpcRequest>() {
            @Override
            public void onNext(UploadObjectGrpcRequest uploadObjectGrpcRequest) {
                GrpcResultDTOV2 grpcResultDTOV2 = uploadObject(uploadObjectGrpcRequest);
                responseObserver.onNext(grpcResultDTOV2);
            }

            @Override
            public void onError(Throwable e) {
                responseObserver.onCompleted();
            }

            @Override
            public void onCompleted() {
                responseObserver.onCompleted();
            }
        };
    }

    @Override
    public StreamObserver<UploadObjectsGrpcRequest> uploadObjects(StreamObserver<GrpcResultDTOV3> responseObserver) {
        return new StreamObserver<UploadObjectsGrpcRequest>() {
            @Override
            public void onNext(UploadObjectsGrpcRequest uploadObjectsGrpcRequest) {
                GrpcResultDTOV3 grpcResultDTOV3 = uploadObjects(uploadObjectsGrpcRequest);
                responseObserver.onNext(grpcResultDTOV3);
            }

            @Override
            public void onError(Throwable e) {
                responseObserver.onCompleted();
            }

            @Override
            public void onCompleted() {
                responseObserver.onCompleted();
            }
        };
    }

    private GrpcResultDTOV2 uploadObject(UploadObjectGrpcRequest request) {
        InnerUploadObjectRequest uploadObjectRequest = new InnerUploadObjectRequest(request.getBucketName(), request.getObjectName(), buildFileMetaData(request.getFile()));
        uploadObjectRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV2(defaultEndpoint.uploadObject(uploadObjectRequest));
    }

    private FileMetaData buildFileMetaData(FileMetaDataGrpcRequest request) {
        return new FileMetaData(request.getData().toByteArray(), request.getContentType(), request.getSize(), request.getFileName());
    }

    private GrpcResultDTOV3 uploadObjects(UploadObjectsGrpcRequest request) {
        InnerUploadObjectsRequest uploadObjectsRequest = new InnerUploadObjectsRequest(request.getBucketName(), request.getFolder(),
                request.getFilesList().stream()
                        .map(fileMetaDataGrpcRequest -> buildFileMetaData(fileMetaDataGrpcRequest))
                        .collect(Collectors.toList()));
        uploadObjectsRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV3(defaultEndpoint.uploadObjects(uploadObjectsRequest));
    }

    @Override
    public void uploadLocalObject(UploadLocalObjectGrpcRequest request, StreamObserver<GrpcResultDTOV2> responseObserver) {
        responseObserver.onNext(uploadLocalObject(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV2 uploadLocalObject(UploadLocalObjectGrpcRequest request) {
        UploadLocalObjectRequest uploadLocalObjectRequest = new UploadLocalObjectRequest(request.getBucketName(), request.getObjectName(), request.getFileName());
        uploadLocalObjectRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV2(defaultEndpoint.uploadLocalObject(uploadLocalObjectRequest));
    }

    @Override
    public void uploadLocalObjects(UploadLocalObjectsGrpcRequest request, StreamObserver<GrpcResultDTOV3> responseObserver) {
        responseObserver.onNext(uploadLocalObjects(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV3 uploadLocalObjects(UploadLocalObjectsGrpcRequest request) {
        UploadLocalObjectsRequest uploadLocalObjectsRequest = new UploadLocalObjectsRequest(request.getBucketName(), request.getFolder(), toStringList(request.getFileNamesList()));
        uploadLocalObjectsRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV3(defaultEndpoint.uploadLocalObjects(uploadLocalObjectsRequest));
    }

    @Override
    public void downloadObject(DownloadObjectGrpcRequest request, StreamObserver<GrpcResultDTOV6> responseObserver) {
        responseObserver.onNext(downloadObject(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV6 downloadObject(DownloadObjectGrpcRequest request) {
        DownloadObjectRequest downloadObjectRequest = new DownloadObjectRequest(request.getBucketName(), request.getObjectName());
        downloadObjectRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV6(defaultEndpoint.downloadObject(downloadObjectRequest));
    }

    @Override
    public void downloadObjects(DownloadObjectsGrpcRequest request, StreamObserver<GrpcResultDTOV6> responseObserver) {
        responseObserver.onNext(downloadObjects(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV6 downloadObjects(DownloadObjectsGrpcRequest request) {
        DownloadObjectsRequest downloadObjectsRequest = new DownloadObjectsRequest(request.getBucketName(), request.getFolder(), request.getFileName());
        downloadObjectsRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV6(defaultEndpoint.downloadObjects(downloadObjectsRequest));
    }

    @Override
    public void removeObject(RemoveObjectGrpcRequest request, StreamObserver<GrpcResultDTOV2> responseObserver) {
        responseObserver.onNext(removeObject(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV2 removeObject(RemoveObjectGrpcRequest request) {
        RemoveObjectRequest removeObjectRequest = new RemoveObjectRequest(request.getBucketName(), request.getUrl());
        removeObjectRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV2(defaultEndpoint.removeObject(removeObjectRequest));
    }

    @Override
    public void removeObjects(RemoveObjectsGrpcRequest request, StreamObserver<GrpcResultDTOV3> responseObserver) {
        responseObserver.onNext(removeObjects(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV3 removeObjects(RemoveObjectsGrpcRequest request) {
        RemoveObjectsRequest removeObjectsRequest = new RemoveObjectsRequest(request.getBucketName(), toStringList(request.getUrlsList()));
        removeObjectsRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV3(defaultEndpoint.removeObjects(removeObjectsRequest));
    }

    private List<String> toStringList(ProtocolStringList dataList) {
        if (Objects.isNull(dataList)) return null;
        List<ByteString> byteStrings = dataList.asByteStringList();
        if (CollectionUtils.isEmpty(byteStrings)) return null;
        return byteStrings.stream()
                .map(byteString -> byteString.toStringUtf8())
                .collect(Collectors.toList());
    }

    @Override
    public void removeObjectsCurrFolder(RemoveObjectsCurrBucketAndFolderGrpcRequest request, StreamObserver<GrpcResultDTOV3> responseObserver) {
        responseObserver.onNext(removeObjectsCurrFolder(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV3 removeObjectsCurrFolder(RemoveObjectsCurrBucketAndFolderGrpcRequest request) {
        RemoveObjectsCurrBucketAndFolderRequest removeObjectsCurrBucketAndFolderRequest = new RemoveObjectsCurrBucketAndFolderRequest(request.getBucketName(), request.getFolder());
        removeObjectsCurrBucketAndFolderRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV3(defaultEndpoint.removeObjects(removeObjectsCurrBucketAndFolderRequest));
    }

    @Override
    public void copyObject(CopyObjectGrpcRequest request, StreamObserver<GrpcResultDTOV2> responseObserver) {
        responseObserver.onNext(copyObject(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV2 copyObject(CopyObjectGrpcRequest request) {
        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(request.getBucketName(), request.getSourceObjectName(), request.getTargetObjectName());
        copyObjectRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV2(defaultEndpoint.copyObject(copyObjectRequest));
    }

    @Override
    public void signedUrl(SignedUrlGrpcRequest request, StreamObserver<GrpcResultDTOV2> responseObserver) {
        responseObserver.onNext(signedUrl(request));
        responseObserver.onCompleted();
    }

    private GrpcResultDTOV2 signedUrl(SignedUrlGrpcRequest request) {
        SignedUrlRequest signedUrlRequest = new SignedUrlRequest(request.getBucketName(), request.getObjectName());
        signedUrlRequest.setOssName(request.getOssName());
        return GrpcResultDTOUtil.successV2(defaultEndpoint.signedUrl(signedUrlRequest));
    }

}
